﻿using ICSharpCode.AvalonEdit.CodeCompletion;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit;
using System.Collections.Generic;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows;
using System;
using System.Windows.Media;
using System.Windows.Documents;

namespace CryForLua_wpf_AvEd.CodeCompletion
{
    public class CompletionData : ICompletionData
    {
        public CompletionData(string text, string desc, List<CodeTable.LuaParameter> paramList)
        {
           
            this.Text = text;
            this.description = desc;
            this.paramsListString = "";
            this.paramData = paramList;

            foreach (CodeTable.LuaParameter param in paramList)
            {
                this.paramsListString += param.name + ": " + param.description + "\n";
            }
        }

        public System.Windows.Media.ImageSource Image
        {
            get { return null; }
        }

        public string Text { get; private set; }
        public double Priority { get; private set; }
        public string description { get; private set; }
        public string paramsListString { get; private set; }
        public List<CodeTable.LuaParameter> paramData { get; private set; }

        private TextArea m_textArea = null;
        private int m_nCurrentParameter = 0;
        private bool m_bShowParamHelper = true;

        // Use this property if you want to show a fancy UIElement in the list.
        public object Content
        {
            get { return this.Text; }
        }

        public object Description
        {
            get { return "Description for " + this.Text + "\n" + this.description + "\nPARAMS:\n" + this.paramsListString; }

        }


        public void Complete(TextArea textArea, ISegment completionSegment,
            EventArgs insertionRequestEventArgs)
        {
            // TODO
            // Take other completion items into consideration, such as keywords
            // They don't have any parenthesises

            m_textArea = textArea;
           
            int insertionLength = 0;

            if (!Text.Contains("("))
            {
                insertionLength = Text.Length;
            }
            else
            {
                insertionLength = Text.IndexOf('(') + 1;
                if (paramsListString == "")
                    insertionLength++;
            }

            if (MainWindow.IsCompletionWindowShowingGlobals)
            {
                // Gotta adjust so it replaces already tyed characters completely (Always missed 1 character)
                // It's somewhat ugly but works.
                AnchorSegment seg = completionSegment as AnchorSegment;

                AnchorSegment newSeg = new AnchorSegment(textArea.Document, seg.Offset - 1, seg.Length + 1);

                FinishCompletion(newSeg, this.Text.Substring(0, insertionLength));
                MainWindow.IsCompletionWindowShowingGlobals = false;

                
                return;
            }

            // For the completion, only use the funciton name + (
            FinishCompletion(completionSegment, this.Text.Substring(0, insertionLength));
        }

        void FinishCompletion(ISegment compSeg, string sText)
        {
            m_textArea.Document.Replace(compSeg, sText);

            if (paramData != null && paramData.Count != 0)
            {
                m_textArea.TextEntering += textArea_TextEntering;
                m_bShowParamHelper = true;
                m_textArea.KeyUp += m_textArea_KeyDown;
                ShowParamHelperToolTip();
            }
        }

        void m_textArea_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            if (e.Key == System.Windows.Input.Key.Escape)
            {
                CloseParamHelperToolTip();
            }

            CheckStillInFunctionParamHead();
            SetCurrentParam();
        }

         void CheckStillInFunctionParamHead()
         {
             string sText = m_textArea.Document.GetText(0, m_textArea.Caret.Offset);

             int openPos = sText.LastIndexOf('(', sText.Length - 1);
             int closePos = sText.LastIndexOf(')', sText.Length - 1);

             if (closePos > openPos || (closePos == openPos && closePos == -1))
             {
                 CloseParamHelperToolTip();
                 m_bShowParamHelper = false;
             }
         }

         void CloseParamHelperToolTip()
         {
             ToolTip tip = m_textArea.ToolTip as ToolTip;
             if (tip != null)
                 tip.IsOpen = false;

             m_textArea.TextEntering -= textArea_TextEntering;
             m_textArea.KeyUp -= m_textArea_KeyDown;
             m_bShowParamHelper = false;
         }

        void SetCurrentParam()
        {
            if (!m_bShowParamHelper)
                return;
            string sText = m_textArea.Document.GetText(0, m_textArea.Caret.Offset);

            int commacount = 0;

            for (int i = sText.Length - 1; i >= 0; --i)
            {
                char currchar = sText[i];

                if (currchar == ',')
                {
                    ++commacount;
                }
                else if (currchar == '(')
                {
                    break;
                }
            }

            m_nCurrentParameter = commacount;
            ShowParamHelperToolTip();
         
        
        }

        void textArea_TextEntering(object sender, System.Windows.Input.TextCompositionEventArgs e)
        {
           if (e.Text[0] == ')' || !m_bShowParamHelper)
            {
                CloseParamHelperToolTip();
            }
        }

        public void ShowParamHelperToolTip()
        { 
            if (paramData != null && paramData.Count != 0)
            {
                ToolTip curTip = m_textArea.ToolTip as ToolTip;
                if (curTip != null)
                    curTip.IsOpen = false;

                // Some parameters don't get their own entry
                if (m_nCurrentParameter > paramData.Count - 1)
                    return;

             

                ToolTip tip = new ToolTip();
                RichTextBox box = new RichTextBox();
                box.MaxWidth = 200;
                box.IsReadOnly = true;
                box.Background = Brushes.LightGoldenrodYellow;

             

                box.Document.Blocks.Clear();
                box.Document.Blocks.Add(new Paragraph(new Run(paramData[m_nCurrentParameter].name + ":")));
                box.Document.Blocks.FirstBlock.FontWeight = FontWeights.Bold; 
                box.Document.Blocks.Add(new Paragraph(new Run(paramData[m_nCurrentParameter].description)));
                //box.AppendText(sToolTipText);

                tip.Content = box ;
               
                //tip.MaxWidth = 50;
                tip.PlacementTarget = m_textArea;
                tip.StaysOpen = true;

                tip.CustomPopupPlacementCallback = new CustomPopupPlacementCallback(PlaceParamToolTip);

                tip.Placement = System.Windows.Controls.Primitives.PlacementMode.Custom;
               
                

                tip.IsOpen = true;

                m_textArea.ToolTip = tip;

                
            }
        }

        public CustomPopupPlacement[] PlaceParamToolTip(Size popupSize,
                                                        Size targetSize,
                                                        Point offset)
        {

            Point caretPos = m_textArea.Caret.CalculateCaretRectangle().BottomLeft;
            CustomPopupPlacement placement1 =
               new CustomPopupPlacement( caretPos, PopupPrimaryAxis.Vertical);

            CustomPopupPlacement placement2 =
                new CustomPopupPlacement(caretPos, PopupPrimaryAxis.Horizontal);

            CustomPopupPlacement[] ttplaces =
                    new CustomPopupPlacement[] { placement1};
            return ttplaces;
        }
 
    }
}